var assigned_to_optons = ''; //定义全局变量，记录重新排序后的指派人options
$(function() {
	let curUrl = decodeURIComponent(window.location.href);
	// 如果存在logout退出按钮，那么退出的时候记录一个退出标记
	if($('a.logout').length>0){
		$('a.logout').click(function(){
			sessionStorage.setItem("logout", "1");
		});
	}
	//如果是登陆页面
	if (curUrl.lastIndexOf('login') > -1) {
		login();
	}
	//如果是项目列表页面
	if ('/redmine/projects' == location.pathname) {
		projectList();
	}
	
	let issue = /\/redmine\/issues\/[1-9][0-9]*/;
	//如果是问题页面
	if (issue.test(location.pathname)) {
		issues();
	}
	//如果是创建子任务页面
	let nIssue = /\/issues\/new\?issue/;
	if(nIssue.test(curUrl)){
		let param = curUrl.substring(curUrl.indexOf('?')+1).split('&');
		//如果包含指定参数，就是创建子问题页面
		if(param[0].indexOf('parent_issue_id') > 0 && param[2].indexOf('type')==0 ){
			// console.table(param);
			newIssue(param);
		}
	}
});
/**
 * 判断当前登录页面
 */
async function login() {
	let user ;
	// 从浏览器插件存储中获取用户信息
	await getUser().then(items=>{
		user = items;
	});
	let logout = sessionStorage.getItem("logout");
	$('#username').val(user.username);
	$('#password').val(user.password);
	// 增加提醒信息
	$('#password').parent().parent().next('tr').children().eq(1).text('Redmine助手工具会在后台使用该用户轮询最新问题清单');
	// 给登录按钮增加事件，登录时修改退出状态为正常登录，登录时将账号密码提交到bg保存到浏览器存储中
	$('[name=login]').click(async function(){
		// 用户退出标记修改为正常登录
		sessionStorage.removeItem("logout");
		// 这里的同步操作没有意义，还没接收到返回值，页面就由于submit自动提交已经刷新了，但是不影响业务逻辑
		logout = await sendMsg({username:$('#username').val(),password:$('#password').val()});
	});
	// 用户是否主动退出登录、是否上次登陆失败、账号密码不为空
	if(!logout==1 && $('div#flash_error').length == 0 && $('#username').val().length>0 && $('#password').val().length>0){
		//等待1秒提交更新
		setTimeout("$('[name=login]').click()", 1000);
	}
}
/**
 * 项目列表页面将和博士2019项目移动到最前面
 */
function projectList() {
	//定义一个临时数据，存放顺序改变的dom
	let tli = new Array();
	//遍历所有li
	$('li.root').each(function() {
		if ($(this).find('a.my-project').text() === '2.和博士2019') {
			//找到和博士2019放到最前面
			tli.unshift(this);
		} else {
			//其他元素按顺序从后面添加进入数组
			tli.push(this);
		}
	});
	//ul元素置空重写入顺序调整后的li
	$('ul.projects.root').empty();
	$('ul.projects.root').append(tli);
}

/**
 * 获取用户信息
 */
function getUser(){
  return new Promise((resolve,reject) => {
      // 读取数据，第一个参数是指定要读取的key以及设置默认值
    chrome.storage.sync.get(['username','password'], function(user) {
      return resolve(user);
    });
  })
}
/**
 * 向bg发送消息
 */
function sendMsg(message){
  return new Promise((resolve,reject) => {
		// 不能直接调用bg，通过消息方式进行调用
		chrome.runtime.sendMessage(message, function(response) {
			console.log('账号保存结果：' + response);
			return resolve(response);
		});
  })
}
/**
 * 问题页面处理
 */
function issues() {
	// 统计问题页面的子任务和缺陷数量
	// 增加一个统计按钮，在子任务后面
	if($('div#issue_tree > form').length > 0){
		$('div#watchers').after('<div id="count"> <div class="contextual"> <a id="iCount" href="#">开始统计</a> </div><h3 id="CountResult">问题统计：</h3>  </div>');
		//增加缓存设置，刷新页面再次读取统计信息，缓存的有效期，刷新时间等需要考虑。使用session缓存，按照页面ID进行存储
		let content = sessionStorage.getItem($('h2:first').text().split('#')[1]);
		if(content != null){
			$('h3#CountResult').after(content);
			$('a#iCount').text('重新统计');
		}
	}
	// 子任务统计计算
	$('#iCount').click(
		async function(){
			// 防止重复点击，每次清空统计结果列表元素
			$('ul#ulResult').remove();
			$('a#iCount').hide();
			let issues = new Array();
			//使用对象构造器，每次赋值都创建新对象
			function issue (type,number,subject,url,status,assigned){
				this.type = type; //类型：缺陷、任务、需求
				this.number = number; //任务编号 #11111
				this.subject = subject; //任务标题
				this.url = url; //问题访问地址
				this.status = status; //问题状态：新建、已解决、已关闭
				this.assigned = assigned;　//问题处理人
			}
			let it = $('div#issue_tree > form td.subject > a');
			//获取子任务集合
			for (const i of it) {
				// 获取问题url
				let url = $(i).attr('href');
				// 可以考虑使用异步操作，同时发起多个请求
				let html =await getIssue(url);
				let $h = $(html);
				// console.log(html);
				let t = $h.find('h2:first').text().split(' ');
				// 获取任务类型 缺陷、任务、需求
				let type = t[0];
				let number = t[1];
				// 获取任务标题
				let subject = $h.find('div.subject h3').text();
				// 类型判断，如果缺陷中的需求确认类型，就标记为需求
				if(type === '缺陷'){
					if($h.find('div.cf_6.attribute > div.value').text() === '需求设计'){
						type = '需求';
					}
				}
				let status = $h.find('div.status.attribute > div.value').text();
				// 获取问题解决人
				let assigned = $h.find('div#history > div.journal i:contains("已解决"):first').parents('div:first').find('a.user.active').text();
				// 如果问题解决人为空，就获取问题最后指派人
				if(assigned === ''){
					assigned = $h.find('div#history > div.journal h4:last').find('a.user.active').text();
				}
				issues.push(new issue(type,number,subject,url,status,assigned));
			};
			// console.log(JSON.stringify(issues));
			let zs= qx = rw = xq = 0; //定义总数、任务数、缺陷数、需求数
			zs = issues.length; // 总数
			let assigneds = new Map(); //任务指派人集合
			for (const i of issues) {
				let type = i.type;
				switch(i.type){
					case '缺陷':
						qx++;
						break;
					case '任务':
						rw++;
						break;
					case '需求':
						xq++;
						break;
					default:
						break
				}
				// 根据任务解决人进行分组
				let a = i.assigned;
				let value = assigneds.get(a);
				// 如果集合中没有该用户，就新增
				if(assigneds.has(a)){
					value += i.number;
				}else{
					value = i.number;
				}
				assigneds.set(a,value);
			}
			//生成统计结果
			let content = `<ul id="ulResult" class="queries"> <li>总计包含问题： ${zs} </li> <li>任务： ${rw} </li> <li>缺陷： ${qx} </li> <li>需求： ${xq} </li>`;
			for (const a of assigneds) {
				let temp = a[1].split('#');  //#分割第一个为空
				content+=`<li>${a[0]} 相关问题 ${temp.length-1} 个：`;
				for (let i = 1; i < temp.length; i++) {
					let e = temp[i];
					let t = issues.find((item)=>{
						return item.number === '#'+e;
					});
					content += `<a class="issue" ${t.type === '缺陷'?"style=color:#f00":t.type === '需求'?"style=color:#00c600":""} href="/redmine/issues/${e}" target="_blank">${t.number} </a> `;
				}
				content += `</li>`;
			}
			content += `</ul>`;
			sessionStorage.setItem($('h2:first').text().split('#')[1],content);
			$('h3#CountResult').after(content);
			$('a#iCount').text('重新统计');
			$('a#iCount').show();
		}
	);


	// $('div.description').after('<div><button id="notify">发送通知</button></div>');
  // $('#notify').click(
	// 	function(){
	// 		chrome.runtime.sendMessage({msg: '字数统计工具可方便的统计出字符个数，并且能够分别统计出中文字符，英文字符，标点符号的个数，文字长度以及行数，小'}, function(response) {
	// 			console.log('收到来自后台的回复：' + response);
	// 		});
	// 	}
	// );

	//给增加按钮增加一个弹窗，选择增加android、ios、pc、api，将父任务名称拼接好传递过去
	//获取创建子任务链接
	let newIssue = decodeURIComponent($('div#issue_tree > div.contextual > a').attr('href'));
	//将子任务强制设置为任务类型
	if(newIssue.substring(newIssue.lastIndexOf('=')+1) != '5'){
		newIssue = newIssue.substring(0,newIssue.lastIndexOf("=")+1)+'5';
	}
	//获取父任务标题
	let subject = $('div.subject > div  h3').text();
	//生成不同终端的任务链接
	let android = newIssue+'&type=1&subject='+subject+'-android"target="_blank"';
	let ios = newIssue+'&type=2&subject='+subject+'-ios" target="_blank"';
	let pc = newIssue+'&type=3&subject='+subject+'-pc" target="_blank"';
	//取消新增按钮的链接跳转
	$('div#issue_tree > div.contextual > a').attr('href', '#');
	//增加点击弹窗事件
	$('div#issue_tree > div.contextual > a').click(
		function() {
			layer.open({
				// type: 1, //1页面
				shadeClose: true, //点击遮罩关闭
				skin: 'layui-layer-lan', //加上边框
				// area: ['320px', '270px'], //宽高
				scrollbar: false,
				title: '选择子任务类型',
				//type类型： 1 android, 2 ios, 3 pc
				content: '<div><p><a href="'+android+'>增加android子任务</a></p><p><a href="'+ios+'>增加ios子任务</a></p><p><a href="'+pc+'>增加PC子任务</a></p></div>'
			});
		}
	);
	let all_attributes = document.querySelector('div#update > form#issue-form > div.box > fieldset.tabular > div#all_attributes');
	let issue_assigned_to_id = document.querySelector('select#issue_assigned_to_id');
	/**
	 * 经过跟踪调试发现虽然能够捕获  issue_assigned_to_id 的改变事件，
	 * 但是redmine在加载的时候会把整个div重新加载多次，
	 * 每次加载都会覆盖 issue_assigned_to_id。
	 * 因此只能针对 all_attributes 这个 div 进行监控和修改排序
	 */
	all_attributes.addEventListener("DOMSubtreeModified", function(e) {
		let node = $(e.target);
		//当all_attributes被重载的时候，重新对下拉框进行排序
		if('all_attributes'==node.attr('id')){
			//只有指派人列表没有排序标记的时候才触发重新排序
			optionSort();
			// setSelected();
		}
	});
	//设置全局的class样式，以取代layer默认样式中的图片文件路径
	addClass('body .layui-layer-ico{ background:url('+chrome.extension.getURL("layer/theme/default/icon.png")+') no-repeat;}');
	addClass('body .layui-layer-iconext{background:url('+chrome.extension.getURL("layer/theme/default/icon-ext.png")+') no-repeat;}');
	addClass('body .layui-layer-load{background:url('+chrome.extension.getURL("layer/theme/default/loading-1.gif")+') #eee center center no-repeat;}');
	addClass('body .layui-layer-loading .layui-layer-content{width:60px; height:24px; background:url('+chrome.extension.getURL("layer/theme/default/loading-0.gif")+') no-repeat;}');
	addClass('body .layui-layer-loading .layui-layer-loading1{width:37px; height:37px; background:url('+chrome.extension.getURL("layer/theme/default/loading-1.gif")+') no-repeat;}');
	addClass('body .layui-layer-loading .layui-layer-loading2, .layui-layer-ico16{width:32px; height:32px; background:url('+chrome.extension.getURL("layer/theme/default/loading-2.gif")+') no-repeat;}');
	// addClass('body .icon-download{ background-image:url('+chrome.extension.getURL("img/download.jpg")+');}');
	//layer图片查看json对象
	let imgJson = {title: "图片查看", id: 123,start: 0,data: []};
	//使用对象构造器，每次赋值都创建新对象
	function imgData (alt,pid,src,thumb){
		this.alt = alt;
		this.pid = pid;
		this.src = src;
		this.thumb = thumb;
	}
	let imgs = new Array();
	//将所有图片链接替换掉
	$('div.attachments>p>a.icon.icon-attachment').each(function(){
		let imgRegex = "(.jpg|.png|.gif|.ps|.jpeg|.bmp)$"; //用于验证图片扩展名的正则表达式
		let videoRegex = "(.mp4|.mkv)$"; //用于验证视频扩展名的正则表达式
		let wordRegex = "(.doc|.docx)$"; //用于验证word扩展名的正则表达式
		let re=new RegExp(imgRegex);
		let href = $(this).attr('href');
		$(this).after('&nbsp;&nbsp;<a title="下载" href="'+href+'">下载</a>');
		//修改图片链接属性
		if (re.test(href.toLowerCase())){
			$(this).attr('url',href); //加入一个自定义属性存储图片链接
			$(this).attr('href','javascript:void(0)'); //取消链接属性
			imgs.push(new imgData($(this).text(),'',href,href));
		}
		//修改视频链接属性
		re = new RegExp(videoRegex);
		if (re.test(href.toLowerCase())){
			$(this).attr('video',href); //加入一个自定义属性存储视频链接
			$(this).attr('href','javascript:void(0)'); //取消链接属性
			// 必须提前添加视频元素才能正常获取视频宽高
			$('div.description').after('<div><video id="'+href.split('/')[4]+'" src="'+href+'" controls="controls" preload="meta" hidden="hidden"></video></div>');
		}
		// 修改word文件查看方式
		re = new RegExp(wordRegex);
		if (re.test(href.toLowerCase())){
			// 使用xdoc在线打开查看，需要配置外网访问地址
			href = 'http://www.xdocin.com/xdoc?_func=to&_format=html&_cache=1&_xdoc=http://60.213.47.147:50000/'+href;
			$(this).attr('href',href); //修改word链接属性
			$(this).attr('target',"_blank");
			//下一步考虑引入xdoc在线转换和查看
		}
	});
	//将图片数组塞入json中
	imgJson.data=imgs;
	//增加点击弹窗事件，弹出图片查看窗口
	$('div.attachments>p>a.icon.icon-attachment[url]').click(
		async function() {
			let imgarea = [];
			let src = $(this).attr('url');
			let title = $(this).text();
			// 预加载图片获取图片宽高
			await loadImage(src).then(img=>{
				// 图片压缩控制，layer的图片压缩仅对photo起作用，这里需要手动实现
				imgarea = calImgZip(img.width,img.height);;
			});
			
			let attachment = '<div><img src="'+$(this).attr('url')+'" width="'+imgarea[0]+'" height="'+imgarea[1]+'" class=""></div>';
			/**
			 * 由于layer会计算标题高度，因此最大高度需要增加一个默认值出来
			 * 如果设置area，那么宽高会显示在图片image的上一层div里面写死
			 * 如果设置max，那么上一层div里面不会写死，使用max图片下面的空白区域相对较小
			 */
			layer.open({
				id: 1,
				type: 1,
				title: title,
				maxmin: true,
				scrollbar: false,
				// offset: ['50px','100px'], //原来没有设置图片尺寸的时候必须固定显示位置
				// area: [imgarea[0] +'px', imgarea[1]+50 +'px'], //即便加上了标题高度，下面显示的空白区域相对较大
				//设置最大宽高，area必须是默认值
				maxWidth: imgarea[0]+10,
				maxHeight: imgarea[1]+50,  //layer自动计算增加一个标题高度默认值
				skin: 'layui-layer-nobg', //没有背景色
				shadeClose: true,
				content: attachment,
			  });
			
		}
	);
	//增加一个轮播图查看按钮，使用layer图片查看
	$('div.attachments>div.contextual>a.icon-only.icon-edit').before('<a id="viewer" href="#">图片轮播图查看</a>&nbsp;&nbsp;&nbsp;');
	$('#viewer').click(
		function(){
			//动态生成一个json，然后赋值调用
			layer.photos({
				photos: imgJson,
				anim: 5 //0-6的选择，指定弹出图片动画类型，默认随机（请注意，3.0之前的版本用shift参数）
			});
		}
	);
	// 视频文件查看，在线播放
	$('div.attachments>p>a.icon.icon-attachment[video]').click(
		function(){
			// 从视频链接处理时预设值的video元素中获取原始宽高
			let width = $('video#'+$(this).attr('video').split('/')[4]+'')[0].videoWidth;
			let height = $('video#'+$(this).attr('video').split('/')[4]+'')[0].videoHeight;
			// 根据屏幕大小进行宽高压缩换算
			let area = calImgZip(width,height);
			let content = '<div><video src="'+$(this).attr('video')+'" width="'+area[0]+'" height="'+area[1]+'" autoplay=true controls="controls"></video></div>';
			layer.open({
				type: 1,
				title: false,
				shade: 0.8,
				closeBtn: 0,
				scrollbar: false,
				shadeClose: true,
				content: content
			});
		}
	);
	//页面首次加载初始化排序
	optionSort();
	// setSelected();
}

/**
 * 子任务页面处理
 * @param {*} param 
 */
function newIssue(param) {
	//从链接获取任务标题和任务类型
	let type = param[2].substring(5);
	let subject = param[3].substring(8);
	// console.log(type+' param '+subject);
	$('#issue_tracker_id').val(5);
	//设置标题
	$('#issue_subject').val(subject);
	$('#issue_description').text('详见父任务。');
	all_attributes.addEventListener("DOMSubtreeModified", function(e) {
		let node = $(e.target);
		// console.log(e);
		// console.log(e.target);
		//当all_attributes被重载的时候，重新对下拉框进行排序
		if('all_attributes'==node.attr('id')){
			//只有指派人列表没有排序标记的时候才触发重新排序
			optionSort();
			//根据类型选择任务指派人
			// switch (type){
			// 	case '1':
			// 		//android
			// 		$('#issue_assigned_to_id').val(18);
			// 		break;
			// 	case '2':
			// 		//ios
			// 		$('#issue_assigned_to_id').val(53);
			// 		break;
			// 	default:
			// 		break;
			// }
		}
	});
	optionSort();
	//根据类型选择任务指派人
	// switch (type){
	// 	case '1':
	// 		//android
	// 		$('#issue_assigned_to_id').val(18);
	// 		break;
	// 	case '2':
	// 		//ios
	// 		$('#issue_assigned_to_id').val(53);
	// 		break;
	// 	default:
	// 		break;
	// }
}
/**
 * 对指派人下拉框进行重新排序
 */
function optionSort(){
	// console.log('optionSort被触发');
	let users = new Array();
	//遍历指派人option，取出所有姓名
	$('select#issue_assigned_to_id option').each(function() {
		//姓名拼接value，排序之后再拆开
		users.push($(this).text()+'`'+$(this).val());
	});
	//对姓名进行中文排序
	users.sort(function(a,b) {
		return a.localeCompare(b, 'zh-CN');
	});
	//排序反转
	// users.reverse();
	/**
	 * 将重新排序之后的指派人Array重组成option放入select
	 * <option value="52">严茂奇</option>
	 * 判断如果全局设置的assigned_to_optons不为空才重新执行排序，否则就直接插入
	 * 由于DOM会反复加载几十次，这里使用一个全局变量存储排序后的options，避免每次都重新计算排序
	 * 给不同部门的人着色？
	 */
	if(assigned_to_optons.length == 0){
		for(i = 0,len=users.length; i < len; i++) {
			let user = users[i].split('`');
			let value = user[1];
			let name = user[0];
			assigned_to_optons += '<option value="'+value+'">'+name+'</option>';
		}
	}
	//标记一个是否已重新排序的属性，用来避免DOM监控的死循环。
	$('select#issue_assigned_to_id').attr('sort','true'); 
	//重新加载option
	$('select#issue_assigned_to_id').empty();
	$('select#issue_assigned_to_id').append(assigned_to_optons);
}
/**
 * 设置下拉选择框的默认值
 */
function setSelected(sid){
	//根据问题状态设置默认指派人
	//获取问题状态
	let statusid = $('select#issue_status_id').find("option:selected").val();
	//获取任务作者id  /redmine/users/8
	let authorId = $('p.author > a.user.active').attr('href').split('/')[3];
	//如果状态是已解决，设置默认选中人为问题发起人
	if(3 == statusid){
		//已解决的默认指派给测试经理
		$('select#issue_assigned_to_id').val(36);
		//填入请求测试语句
		$('div.jstEditor > textarea#issue_notes').text('已完成，请安排测试。');
	}else{
		//其他状态下设置默认选中人为问题发起人
		$('select#issue_assigned_to_id').val(authorId);
		$('div.jstEditor > textarea#issue_notes').text('');
	}
	//如果传入了选中项ID，就设置为选中
	if(sid!=null){
		$('select#issue_assigned_to_id').val(sid);
	}
}
/**
 * 将当前访问地址存入历史记录中
 * 默认记录4个最近访问页面
 * 主要用来判断是否是登录后又退出重新登录的
 * 通过对logout增加click事件主动记录来实现
 * 此方法废弃
 */
function historyUrl(curUrl) {
	//从sessionStorage获取历史访问记录
	let storageUrl = sessionStorage.getItem("historyUrl");
	//定义历史访问记录数组
	let historyUrl;
	if (storageUrl === null) {
		//如果缓存为空,就是首次打开，创建新的访问历史记录数组
		historyUrl = new Array();
	} else {
		//将sessionStorage的历史记录解析成数组
		historyUrl = storageUrl.split(',');
	}
	//如果数组长度超过3，就删除第一个
	if (historyUrl.length > 10) {
		historyUrl.shift();
	}
	//将当前访问地址加入数组中
	historyUrl.push(curUrl);
	// sessionStorage.removeItem('historyUrl');
	sessionStorage.setItem("historyUrl", historyUrl);
}

/**
 * 根据传入的图片路径提前预加载图片，用来获取图片长宽高等信息
 * @param {src} url 
 */
function loadImage(url) {
	// 使用async做同步操作控制
	return new Promise((resolve,reject) => {
		var img = new Image();
		img.src = url; 
		// 如果图片已存在就直接返回
		if(img.complete){
			return resolve(img);
		}
		// 首次加载图片
		img.onload = function(){
			// 置空防止溢出
			img.onload = null;
			return resolve(img);
		};
		img.onerror = function(e){
			img.onerror = null;
			reject(e);
		}; 
	});   
};
/**
 * 传入图片宽高，根据窗口尺寸-100进行计算
 * 如果图片超过窗口尺寸，就按照最大比例进行压缩
 * 返回压缩处理后的图片尺寸
 * return imgarea [width, height];
 * @param {width, height} width, height 
 */
function calImgZip(width, height){
	let winarea = [$(window).width() - 100, $(window).height() - 100];
	let imgarea = [width, height];
	// 图片压缩控制，layer的图片压缩仅对photo起作用，这里需要手动实现
	//如果 实际图片的宽或者高比 屏幕大（那么进行缩放）
	if(imgarea[0]>winarea[0]||imgarea[1]>winarea[1]){
		let wh = [imgarea[0]/winarea[0],imgarea[1]/winarea[1]];//取宽度缩放比例、高度缩放比例
		// console.log(imgarea+'  '+winarea+'  '+wh);
		if(wh[0] > wh[1]){//取缩放比例最大的进行缩放
			imgarea[0] = imgarea[0]/wh[0];
			imgarea[1] = imgarea[1]/wh[0];
		} else if(wh[0] < wh[1]){
			imgarea[0] = imgarea[0]/wh[1];
			imgarea[1] = imgarea[1]/wh[1];
		}
	}
	return imgarea;
}

/**
 * 将css样式的class加入head中
 * @param {String} cssText 
 * IE中有stylesheet数量限制，如果IE使用，应考虑设置全局变量来控制一下存入一个元素中
 */
function addClass(cssText){
	let style = document.createElement('style'), //创建一个style元素
    head = document.head || document.getElementsByTagName('head')[0]; //获取head元素
	style.type = 'text/css'; //这里必须显示设置style元素的type属性为text/css，否则在ie中不起作用
	if(style.styleSheet){ //IE
		let func = function(){
			try{ //防止IE中stylesheet数量超过限制而发生错误
				style.styleSheet.cssText = cssText;
			}catch(e){
				
			}
		}
		//如果当前styleSheet还不能用，则放到异步中则行
		if(style.styleSheet.disabled){
			setTimeout(func,10);
		}else{
			func();
		}
	}else{ //w3c
		//w3c浏览器中只要创建文本节点插入到style元素中就行了
		let textNode = document.createTextNode(cssText);
		style.appendChild(textNode);
	}
	head.appendChild(style); //把创建的style元素插入到head中  
}

  // 请求我的问题列表，按照时间排序
  function getIssue(href){
    return new Promise(function (resolve, reject) {
      $.get(href,function(data){
      // console.log(data);  
      return resolve(data);
      });
    });
	}
	